---
slug: rethinking-fine-grained-components
title: Introducing “slice components”
description: We’ve re-thought the API for fine-grained component rendering.
author: tyler
release: v0.25
date: 2025/08/12
---

We’re happy to announce Waku v0.25 with a brand new API: Slice Components!

We feel the Slices API solves issues reported with the now deprecated Page Part components while also unlocking brand new flexibility with render patterns!

## Components are re-useable across pages

Slices are components that are defined in the `src/pages/_slices` directory. This allows us to re-use slices across pages as any other component would be used.

```
 src/pages
 ├── _slices
 │   ├── one.tsx
 │   └── two.tsx
 └── some-page.tsx
```

And some-page.tsx will be written something like this:

```tsx
import { Slice } from 'waku';

export default function SomePage() {
  return (
    <div>
      <Slice id="one" />
      <Slice id="two" />
    </div>
  );
}

export const getConfig = () => {
  return {
    render: 'static',
    slices: ['one', 'two'],
  };
};
```

Please notice: `slices` must be specified with each of the slice ids in order for Waku to know how to bundle your page without any compiler magic.

The slice id will be the filename. If slices are nested like `src/pages/_slices/one/two.tsx`, the id will be `one/two`.

An example for `src/pages/_slices/one.tsx`:

```tsx
export default function SliceOne() {
  return <p>🍕</p>;
}

export const getConfig = () => {
  return {
    render: 'static', // default is 'static'
  };
};
```

We’re really happy with the new approach and how it will allow simply importing and assembling your components like normal components, while also specifying alternate rendering.

## Lazy Slice Components

`lazy` Slice Components are a new addition with the Slices API. They are Waku’s take on the [server islands feature](https://astro.build/blog/astro-4120/) from Astro. `lazy` allows components to be requested independent from the page they are used on. This is useful for components will be dynamically rendered on otherwise static pages and layouts.

If we re-use the example above, it could be written like this:

```tsx
import { Slice } from 'waku';

export default function SomePage() {
  return (
    <div>
      <Slice id="one" />
      <Slice id="two" lazy fallback={<p>Two is loading...</p>} />
    </div>
  );
}

export const getConfig = () => {
  return {
    render: 'static',
    slices: ['one'], // Note: `two` is lazy so it is not included with the page config
  };
};
```

This makes it so that now you can have a `dynamic` Slice component for slice `two` here, while the rest of the page is static.

## Some breaking changes

We’ve standardized on the following defaults: pages, layouts, and slices are all static by default. API routes are dynamic by default.

This comes with the explicit change of `pages` default render to `'static'`. So any pages that do not currently use `getConfig` should add:

```ts
export const getConfig = () => {
  return {
    render: 'dynamic',
  } as const;
};
```

## There’s more to come

We’re keeping Waku Router minimal and making it even more powerful with this release. We’re really excited to see what you can build with Slices and would love to hear from you on our [Discord server](https://discord.gg/MrQdmzd), [GitHub discussions](https://github.com/wakujs/waku/discussions), or [around](https://x.com/wakujs) [the](https://bsky.app/profile/daishikato.com) [web](https://fosstodon.org/@daishi).

P.S., We have a [few more things](https://github.com/wakujs/waku/issues/24) coming soon!
